package webmarket.jpacontrollers;

import java.util.Iterator;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.EntityType;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;

import webmarket.common.MarkerController;
import webmarket.common.MarkerController.MarkerTypes;
import webmarket.model.ReadLog;

public class LogJpaController extends JpaControllerBase<ReadLog> {
	private static final long serialVersionUID = -2906594319434198609L;

	public LogJpaController() {
		super(ReadLog.class);
	}

	public List<ReadLog> getLogs(String markerName, String sortCol, String sortDir, int limit, int offset) {
		logger.entry("markername:" + markerName, "sortCol:" + sortCol);
		List<ReadLog> result;
		EntityManager em = getEntityManager();
		try {
			CriteriaBuilder cb = em.getCriteriaBuilder();
			CriteriaQuery<ReadLog> cq = em.getCriteriaBuilder().createQuery(ReadLog.class);
			EntityType<ReadLog> readlog = em.getMetamodel().entity(ReadLog.class);
			Root<ReadLog> root = cq.from(readlog);
			Predicate predicate = getPredicate(markerName, cb, readlog, root);
			cq.where(predicate);
			if (StringUtils.isBlank(sortCol)) {
				sortCol = "millis";
			} else if ("username".equals(sortCol)) {
				sortCol = "user";
			}
			Order order = super.getOrder(sortCol, sortDir.equals("desc"), em, root);
			cq.orderBy(order);

			TypedQuery<ReadLog> q = em.createQuery(cq);
			q.setFirstResult(offset);
			q.setMaxResults(limit);
			result = q.getResultList();
		} catch (Throwable e) {
			logger.catching(Level.TRACE, e);
			throw e;
		} finally {
			em.close();
		}
		logger.exit(result);
		return result;
	}

	protected Predicate getPredicate(String markerName, CriteriaBuilder cb, EntityType<ReadLog> readlog, Root<ReadLog> root) {
		Predicate predicate;
		if (!StringUtils.isBlank(markerName)) {
			List<Marker> markers = MarkerController.getAllLeafs(MarkerTypes.valueOf(markerName));
			Expression<Marker> markerexp = root.get(readlog.getDeclaredSingularAttribute("marker", Marker.class));
			Predicate[] predicates = new Predicate[markers.size()];
			Iterator<Marker> markerIterator = markers.iterator();
			for (int i = 0; markerIterator.hasNext(); i++) {
				Marker marker = markerIterator.next();
				Predicate equalPredicate = cb.equal(markerexp, marker);
				predicates[i] = equalPredicate;
			}
			predicate = cb.or(predicates);
		} else {
			predicate = cb.conjunction();
		}
		return predicate;
	}

	public int getCount(String markerName) {
		int count;
		EntityManager em = getEntityManager();
		try {
			CriteriaBuilder cb = em.getCriteriaBuilder();
			CriteriaQuery<Long> cq = em.getCriteriaBuilder().createQuery(Long.class);
			EntityType<ReadLog> readlog = em.getMetamodel().entity(ReadLog.class);
			Root<ReadLog> root = cq.from(readlog);
			Predicate predicate = getPredicate(markerName, cb, readlog, root);
			count = super.getCount(predicate, em, cq, root);
		} catch (Throwable e) {
			logger.catching(Level.TRACE, e);
			throw e;
		} finally {
			em.close();
		}
		return count;
	}
}
